package AndEngineTest.java;

import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnAreaTouchListener;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.Scene.ITouchArea;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.scene.menu.MenuScene;
import org.anddev.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.anddev.andengine.entity.scene.menu.animator.DirectMenuAnimator;
import org.anddev.andengine.entity.scene.menu.item.IMenuItem;
import org.anddev.andengine.entity.scene.menu.item.SpriteMenuItem;
import org.anddev.andengine.entity.shape.IShape;
import org.anddev.andengine.entity.shape.Shape;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.extension.physics.box2d.PhysicsConnector;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import android.view.KeyEvent;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;

public class AndEngineTestActivity extends BaseGameActivity implements IAccelerometerListener, IOnSceneTouchListener, IOnAreaTouchListener, IOnMenuItemClickListener  {
	 // ===========================================================
    // Constants
    // ===========================================================

    /* Initializing the Random generator produces a comparable result over different versions. */
    
    private static final int CAMERA_WIDTH = 720;
    private static final int CAMERA_HEIGHT = 480;
    
    protected static final int MENU_BACK = 0;
    protected static final int MENU_RESET = MENU_BACK + 1;
    protected static final int MENU_QUIT = MENU_RESET + 1;
    
    private static final int GRAVITY = 7000;

    private static final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);

    // ===========================================================
    // Fields
    // ===========================================================

    private Camera mCamera;
    private Scene mScene;
    private PhysicsWorld mPhysicsWorld;
    private BitmapTextureAtlas mBitmapTextureAtlas;
    private TiledTextureRegion mFaceTextureRegion;
    
    protected MenuScene mMenuScene;    
    private BitmapTextureAtlas mMenuTexture;
    protected TextureRegion mMenuResetTextureRegion;
    protected TextureRegion mMenuQuitTextureRegion;
    protected TextureRegion mMenuBackTextureRegion;

    // ===========================================================
    // Constructors
    // ===========================================================

    // ===========================================================
    // Getter & Setter
    // ===========================================================

    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================
    @Override     
    public void onDestroy() {   
    		super.onDestroy();
    }  
    
    public void onCreate() {
    		super.onCreate(null);
    }

    @Override
    public Engine onLoadEngine() {
            this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
            final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera);
            engineOptions.getTouchOptions().setRunOnUpdateThread(true);
            return new Engine(engineOptions);
    }

    @Override
    public void onLoadResources() {
    	/* Textures. */
        this.mBitmapTextureAtlas = new BitmapTextureAtlas(256, 128, TextureOptions.BILINEAR);
        BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");

        /* TextureRegions. */
        this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "smile.png", 0, 0, 2, 1);
        this.mEngine.getTextureManager().loadTexture(this.mBitmapTextureAtlas);
        
        this.mMenuTexture = new BitmapTextureAtlas(256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        this.mMenuBackTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mMenuTexture, this, "menu_back.png", 0, 0);
        this.mMenuResetTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mMenuTexture, this, "menu_reset.png", 0, 50);
        this.mMenuQuitTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mMenuTexture, this, "menu_quit.png", 0, 100);        
        this.mEngine.getTextureManager().loadTexture(this.mMenuTexture);
        
    }
    
    @Override
    public void onResume(){
    	super.onResume();
    	this.enableAccelerometerSensor(this);    	
    }

    @Override
    public Scene onLoadScene() {
    		mScene = new Scene();
    		
    		this.createMenuScene();
    		
    		mScene.setBackground(new ColorBackground(1.0f, 1.0f, 1.0f));
    		
    		this.mScene.setOnSceneTouchListener(this);
    		this.mScene.setOnAreaTouchListener(this);

    		this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, 0), false);
    		
    		final Shape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2);
    		final Shape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2);
    		final Shape left = new Rectangle(0, 0, 2, CAMERA_HEIGHT);
    		final Shape right = new Rectangle(CAMERA_WIDTH - 2, 0, 2, CAMERA_HEIGHT);

    		final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f);
    		PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
    		PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
    		PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
    		PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);

    		this.mScene.attachChild(ground);
    		this.mScene.attachChild(roof);
    		this.mScene.attachChild(left);
    		this.mScene.attachChild(right);
    		mScene.registerUpdateHandler(this.mPhysicsWorld);
    	      
            return mScene;
    }

    @Override
    public void onLoadComplete() {

    }
    
    @Override
    public boolean onKeyDown(final int pKeyCode, final KeyEvent pEvent) {
            if(pKeyCode == KeyEvent.KEYCODE_MENU && pEvent.getAction() == KeyEvent.ACTION_DOWN) {
                    if(this.mScene.hasChildScene()) {
                            /* Remove the menu and reset it. */
                            this.mMenuScene.back();
                    } else {
                            /* Attach the menu. */
                            this.mScene.setChildScene(this.mMenuScene, false, true, true);
                    }
                    return true;
            } else {
                    return super.onKeyDown(pKeyCode, pEvent);
            }
    }

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		// TODO Auto-generated method stub
		if(this.mPhysicsWorld != null) {
			if(pSceneTouchEvent.isActionDown()) {
				this.addFace(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
				return true;
			}
		}
		return false;
	}
	
	 @Override
     public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final ITouchArea pTouchArea, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
             if(pSceneTouchEvent.isActionDown()) {
                     //this.removeFace(pTouchArea);
                     return true;
             }
             return false;
     }

	@Override
	public void onAccelerometerChanged(AccelerometerData pAccelerometerData) {
		final Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX() * GRAVITY / 100, pAccelerometerData.getY() * GRAVITY / 100);
		this.mPhysicsWorld.setGravity(gravity);
		Vector2Pool.recycle(gravity);
		
	}
	
    @Override
    public boolean onMenuItemClicked(final MenuScene pMenuScene, final IMenuItem pMenuItem, final float pMenuItemLocalX, final float pMenuItemLocalY) {
            switch(pMenuItem.getID()) {
            		case MENU_BACK:
            				/* Go back to the scene. */
                        	this.mScene.clearChildScene();
                        	this.mMenuScene.reset();
            				return true;
                    case MENU_RESET:
                            /* Restart the animation. */
                            this.mScene.reset();
                            
                            /* Clear the scene of all physics connectors*/
                            this.resetScene();

                            /* Remove the menu and reset it. */
                            this.mScene.clearChildScene();
                            this.mMenuScene.reset();
                            return true;
                    case MENU_QUIT:
                            /* End Activity. */
                            this.finish();
                            return true;
                    default:
                            return false;
            }
    }	
	
	// ===========================================================
    // Methods
    // ===========================================================
    
    private void resetScene() {
    	// remove all physics connectors    	
    	while(this.mPhysicsWorld.getPhysicsConnectorManager().size() > 0) {
    		final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().get(0);
    		
            this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
            this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());

            this.mScene.unregisterTouchArea(facePhysicsConnector.getShape());
            this.mScene.detachChild(facePhysicsConnector.getShape());    		
    	}    	
        
        System.gc();
    	return;
    }
	
	private void addFace(final float pX, final float pY) {
		/* Quickly twinkling face. */
		final Body body;
//        final AnimatedSprite face = new AnimatedSprite(pX, pY, this.mFaceTextureRegion) {
//            @Override
//            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
//                    this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2, pSceneTouchEvent.getY() - this.getHeight() / 2);
//                    return true;
//            }
//        };
//        body = PhysicsFactory.createCircleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
//        
//        // random wink time so all faces dont blink together
//        final Random generator = new Random();
//        final int iNextNum = generator.nextInt(10);
//        face.animate(100 + (iNextNum * 300));		
		final PhergFace face = new PhergFace(pX, pY, this.mFaceTextureRegion, mPhysicsWorld);
		
		this.mScene.registerTouchArea(face);
		this.mScene.attachChild(face);
        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(face, face.getBody(), true, true));
	}
	
	private void removeFace(final ITouchArea face) {
		final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape((IShape)face);
		facePhysicsConnector.getBody().setLinearVelocity(new Vector2(-1 * GRAVITY,0));
	}

    protected void createMenuScene() {
            this.mMenuScene = new MenuScene(this.mCamera);
            
            final SpriteMenuItem backMenuItem = new SpriteMenuItem(MENU_BACK, this.mMenuBackTextureRegion);
            backMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
            this.mMenuScene.addMenuItem(backMenuItem);
            
            final SpriteMenuItem resetMenuItem = new SpriteMenuItem(MENU_RESET, this.mMenuResetTextureRegion);
            resetMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
            this.mMenuScene.addMenuItem(resetMenuItem);

            final SpriteMenuItem quitMenuItem = new SpriteMenuItem(MENU_QUIT, this.mMenuQuitTextureRegion);
            quitMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
            this.mMenuScene.addMenuItem(quitMenuItem);
            
            // put some space between the buttons 
            final DirectMenuAnimator menuAnimator = new DirectMenuAnimator(40.0f);
            this.mMenuScene.setMenuAnimator(menuAnimator);
            
			this.mMenuScene.buildAnimations();
            this.mMenuScene.setBackgroundEnabled(false);

            this.mMenuScene.setOnMenuItemClickListener(this);
    }
}